﻿using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NewRetail.Application.Components.Dashboard;
using NewRetail.Application.Components.WeChat.CardVoucher.Entity;
using NewRetail.Application.Components.WeChat.CardVoucher.Services;
using NewRetail.Application.Components.WeChat.Model;
using NewRetail.Application.Core;
using NewRetail.Application.Utility.Hubs;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;


namespace NewRetail.Application.Worker
{
    //用户券的状态数据刷新
    public class MemberCardVoucherRefreshingWorker : ApplicationService, ITransientDependency
    {
        #region params
        private readonly ILogger _logger;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly RedLockFactoryWrapper _redLockFactoryWrapper;
        public readonly ICardVoucherService _cardVoucherService;
        private readonly IRepository<UserCouponsInfo> _userCouponsRepository;
        #endregion

        #region 构造
        public MemberCardVoucherRefreshingWorker(ILogger<DashboardRefreshingWorker> logger, RedLockFactoryWrapper redLockFactoryWrapper,
            ICardVoucherService cardVoucherService, IRepository<UserCouponsInfo> userCouponsRepository, IUnitOfWorkManager unitOfWorkManager)
        {
            _logger = logger;
            _redLockFactoryWrapper = redLockFactoryWrapper;
            _unitOfWorkManager = unitOfWorkManager;
            _cardVoucherService = cardVoucherService;
            _userCouponsRepository = userCouponsRepository;
        }
        #endregion

        #region method
        [UnitOfWork]
        public virtual async Task Execute()
        {
            try
            {
                _logger.LogInformation(DateTime.Now.ToString() + "[MemberCardVoucherStatusRefresh]");
                IList<Task> tasks = new List<Task>();
                Task task = TryRefreshMemberCardVoucherStatusAsync();
                tasks.Add(task);
                await Task.WhenAll(tasks);

            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                throw;
            }
        }
        #endregion

        #region 刷新数据
        [UnitOfWork]
        private async Task TryRefreshMemberCardVoucherStatusAsync(CancellationToken cancellationToken = default)
        {
            // resource 锁定的对象
            // expiryTime 锁定过期时间，锁区域内的逻辑执行如果超过过期时间，锁将被释放
            // waitTime 等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
            // retryTime 等待时间内，多久尝试获取一次
            using var distributedLock = await _redLockFactoryWrapper.RedLockFactory.CreateLockAsync(
                resource: $"{nameof(DashboardRefreshingWorker)}",
                expiryTime: TimeSpan.FromMinutes(1),
                waitTime: TimeSpan.FromMinutes(1),
                retryTime: TimeSpan.FromSeconds(3));

            if (distributedLock.IsAcquired)
            {
                var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
                var userCoupons = await dbUserCoupons.Set<UserCouponsInfo>().AsNoTracking().Where(x => string.IsNullOrEmpty(x.couponStatus))?.ToListAsync();
                if (userCoupons != null)
                {
                    var openIdList = userCoupons.GroupBy(x => x.openId).Select(x => x.Key).ToList();
                    foreach(var item in openIdList)
                    {
                        var operateResult = await _cardVoucherService.QuerySaveMarketingFavorUserCouponsAsync(item);
                        if (!string.IsNullOrEmpty(operateResult.Item2))
                        {
                            _logger.LogError("任务修改本地券状态失败！失败券id:" + operateResult.Item2);
                        }
                    }
                }
                    
                _logger.LogInformation("刷新券状态数据成功！");
            }
            else
            {
                _logger.LogInformation("未能拿到锁，存在并发");
            }
        }
        #endregion
    }
}
